home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*
- * canop -
- * Apply global operations to canvases.
- *
- * Paul Haeberli - 1991
- *
- * exports
- *
- void bwonly(mode);
- void canvasop(c,opfunc,arg1,arg2,arg3)
-
- void saturateop(pptr,n,sat,dum1,dum2)
- void copyred(pptr,n,dum1,dum2,dum3)
- void imgexpop(pptr,n,min,max,dum1)
- void gammaop(pptr,n,gam,dum1,dum2)
- void cscaleop(pptr,n,rscale,gscale,bscale)
- void invertop(pptr,n)
- void addnoiseop(pptr,n,mag)
- void quantop(pptr,n,nsteps)
- void duotoneop(pptr,n,rval,gval,bval)
-
- canvas *makestamp(c,maxxsize,maxysize,filter)
- void randcopy(orig,dest)
- void canvastile(tile,dest)
- void convolve3(src,dest,mat)
- *
- */
- #include "stdio.h"
- #include "canvas.h"
- #include "math.h"
- #include "izoom.h"
- #include "lum.h"
- #include "lut.h"
-
- #define STAMPSIZE 100
-
- static int dobwonly;
-
- void bwonly(mode)
- int mode;
- {
- dobwonly = mode;
- }
-
- float frand();
- static applymaptab();
-
- static float clamp(v)
- float v;
- {
- if(v<0.0)
- return 0.0;
- if(v>1.0)
- return 1.0;
- return v;
- }
-
- void canvasop(c,opfunc,arg1,arg2,arg3)
- canvas *c;
- int (*opfunc)();
- float arg1, arg2, arg3;
- {
- long *dptr;
-
- saverect(c,&c->area);
- opfunc(c->data,c->xsize*c->ysize,arg1,arg2,arg3);
- touchcanvas(c);
- flushcanvas(c);
- }
-
- #define DOTWOPIX(p0,p1) \
- ul = ((((pptr[(p1)].r<<16) + pptr[(p0)].r)*RINTLUM)+ \
- (((pptr[(p1)].g<<16) + pptr[(p0)].g)*GINTLUM)+ \
- (((pptr[(p1)].b<<16) + pptr[(p0)].b)*BINTLUM))>>8; \
- pptr[(p0)].r = pptr[(p0)].g = pptr[(p0)].b = ul; \
- pptr[(p1)].r = pptr[(p1)].g = pptr[(p1)].b = (ul>>16);
-
-
- void saturateop(pptr,n,sat,dum1,dum2)
- pixel *pptr;
- int n;
- float sat, dum1, dum2;
- {
- unsigned long ur, ug, ub, ul, l;
- int bw, r, g, b;
- unsigned long *p, pix0, pix1;
- int isat;
-
- if(dobwonly)
- sat = 0;
- isat = 255*sat;
- if(isat == 0) {
- while(n>=8) {
- DOTWOPIX(0,1);
- DOTWOPIX(2,3);
- DOTWOPIX(4,5);
- DOTWOPIX(6,7);
- pptr+=8;
- n-=8;
- }
- while(n--) {
- pptr->r = pptr->g = pptr->b = ILUM(pptr->r,pptr->g,pptr->b);
- pptr++;
- }
- return;
- }
- if(sat>=0.0 && sat<=1.0) {
- while(n--) {
- r = pptr->r;
- g = pptr->g;
- b = pptr->b;
- bw = (256-isat)*ILUM(r,g,b);
- pptr->r = (bw+isat*r)>>8;
- pptr->g = (bw+isat*g)>>8;
- pptr->b = (bw+isat*b)>>8;
- pptr++;
- }
- return;
- }
- while(n--) {
- r = pptr->r;
- g = pptr->g;
- b = pptr->b;
- bw = (256-isat)*ILUM(r,g,b);
- r = (bw+isat*r)>>8;
- g = (bw+isat*g)>>8;
- b = (bw+isat*b)>>8;
-
- if(r&0xffffff00) {
- if(r<0) r = 0; else r = 255;
- }
- pptr->r = r;
- if(g&0xffffff00) {
- if(g<0) g = 0; else g = 255;
- }
- pptr->g = g;
- if(b&0xffffff00) {
- if(b<0) b = 0; else b = 255;
- }
- pptr->b = b;
- pptr++;
- }
- }
-
- void copyred(pptr,n,dum1,dum2,dum3)
- pixel *pptr;
- int n;
- float dum1, dum2, dum3;
- {
- while(n--) {
- pptr->g = pptr->r;
- pptr->b = pptr->r;
- pptr++;
- }
- }
-
- void imgexpop(pptr,n,min,max,dum1)
- pixel *pptr;
- int n;
- float min, max, dum1;
- {
- int i;
- unsigned char tab[256];
- float val, delta;
-
- delta = max-min;
- if(delta<0.0001)
- delta = 0.0001;
- for(i=0; i<256; i++) {
- val = clamp(((i/255.0)-min)/delta);
- tab[i] = ffloor(255.0*val+0.49);
- }
- applymaptab(pptr,n,tab);
- }
-
- #define DOMAP(p) \
- pptr[(p)].r = tab[pptr[(p)].r]; \
- pptr[(p)].g = tab[pptr[(p)].g]; \
- pptr[(p)].b = tab[pptr[(p)].b];
-
- #define DOBWMAP(p) \
- pptr[(p)].r = tab[pptr[(p)].r];
-
- static applymaptab(pptr,n,tab)
- pixel *pptr;
- int n;
- unsigned char tab[256];
- {
- if(dobwonly) {
- while(n>=8) {
- DOBWMAP(0);
- DOBWMAP(1);
- DOBWMAP(2);
- DOBWMAP(3);
- DOBWMAP(4);
- DOBWMAP(5);
- DOBWMAP(6);
- DOBWMAP(7);
- n-=8;
- pptr+=8;
- }
- while(n--) {
- DOBWMAP(0);
- pptr++;
- }
- } else {
- while(n>=8) {
- DOMAP(0);
- DOMAP(1);
- DOMAP(2);
- DOMAP(3);
- DOMAP(4);
- DOMAP(5);
- DOMAP(6);
- DOMAP(7);
- n-=8;
- pptr+=8;
- }
- while(n--) {
- DOMAP(0);
- pptr++;
- }
- }
- }
-
- void gammaop(pptr,n,gam,dum1,dum2)
- pixel *pptr;
- int n;
- float gam, dum1, dum2;
- {
- int i;
- unsigned char tab[256];
-
- for(i=0; i<256; i++)
- tab[i] = ffloor(255.0*pow(i/255.0,gam)+0.49);
- applymaptab(pptr,n,tab);
- }
-
- #define DOMAP3(p) \
- pptr[(p)].r = tab1[pptr[(p)].r]; \
- pptr[(p)].g = tab2[pptr[(p)].g]; \
- pptr[(p)].b = tab3[pptr[(p)].b]; \
-
- #define DOBWMAP3(p) \
- pptr[(p)].r = tab1[pptr[(p)].r];
-
- static applymaptab3(pptr,n,tab1,tab2,tab3)
- pixel *pptr;
- int n;
- unsigned char tab1[256], tab2[256], tab3[256];
- {
- if(dobwonly) {
- while(n>=8) {
- DOBWMAP3(0);
- DOBWMAP3(1);
- DOBWMAP3(2);
- DOBWMAP3(3);
- DOBWMAP3(4);
- DOBWMAP3(5);
- DOBWMAP3(6);
- DOBWMAP3(7);
- n-=8;
- pptr+=8;
- }
- while(n--) {
- DOBWMAP3(0);
- pptr++;
- }
- } else {
- while(n>=8) {
- DOMAP3(0);
- DOMAP3(1);
- DOMAP3(2);
- DOMAP3(3);
- DOMAP3(4);
- DOMAP3(5);
- DOMAP3(6);
- DOMAP3(7);
- n-=8;
- pptr+=8;
- }
- while(n--) {
- DOMAP3(0);
- pptr++;
- }
- }
- }
-
- void cscaleop(pptr,n,rscale,gscale,bscale)
- pixel *pptr;
- int n;
- float rscale, gscale, bscale;
- {
- int i;
- float val;
- unsigned char rtab[256];
- unsigned char gtab[256];
- unsigned char btab[256];
-
- if(dobwonly) {
- rscale = LUM(rscale,gscale,bscale);
- for(i=0; i<256; i++) {
- val = i/255.0;
- rtab[i] = ffloor(255.0*clamp(rscale*val)+0.49);
- }
- applymaptab(pptr,n,rtab);
- } else {
- for(i=0; i<256; i++) {
- val = i/255.0;
- rtab[i] = ffloor(255.0*clamp(rscale*val)+0.49);
- gtab[i] = ffloor(255.0*clamp(gscale*val)+0.49);
- btab[i] = ffloor(255.0*clamp(bscale*val)+0.49);
- }
- applymaptab3(pptr,n,rtab,gtab,btab);
- }
- }
-
- void invertop(pptr,n)
- pixel *pptr;
- int n;
- {
- int i;
- unsigned char tab[256];
-
- for(i=0; i<256; i++)
- tab[i] = 255-i;
- applymaptab(pptr,n,tab);
- }
-
- #define NRTABS (100)
- static long *randvals;
- static unsigned char **rtabs;
- static float curmag = -1.0;
-
- void addnoiseop(pptr,n,mag)
- pixel *pptr;
- int n;
- float mag;
- {
- int i, v, maxdel, idel;
- unsigned char *cptr;
- int curtab;
- long *rptr;
-
- if(mag<=0.0)
- return;
- if(mag>1.0)
- mag = 1.0;
- if(!randvals) {
- randvals = (long *)mymalloc(NRTABS*256*sizeof(long));
- rtabs = (unsigned char **)mymalloc(NRTABS*sizeof(char *));
- for(i=0; i<NRTABS; i++)
- rtabs[i] = (unsigned char *)mymalloc(256*sizeof(char));
- rptr = randvals;
- for(i=0; i<(256*NRTABS); i++)
- *rptr++ = random();
- }
- if(mag != curmag) {
- maxdel = 127*mag;
- rptr = randvals;
- for(i=0; i<NRTABS; i++) {
- cptr = rtabs[i];
- for(v=0; v<256; v++) {
- #ifdef OLDWAY
- idel = maxdel;
- if(v<idel)
- idel = v;
- if((255-v)<idel)
- idel = 255-v;
- #else
- if(v<128)
- idel = v*mag;
- else
- idel = (255-v)*mag;
- #endif
- idel++;
- if(*rptr & 0x80000)
- *cptr++ = v+((*rptr++)%idel);
- else
- *cptr++ = v-((*rptr++)%idel);
- }
- }
- curmag = mag;
- }
- if(mag == 0.0)
- return;
- if(dobwonly) {
- while(n--) {
- curtab = random()%(NRTABS-3);
- pptr->r = rtabs[curtab][pptr->r];
- pptr++;
- }
- } else {
- while(n--) {
- curtab = random()%(NRTABS-3);
- pptr->r = rtabs[curtab++][pptr->r];
- pptr->g = rtabs[curtab++][pptr->g];
- pptr->b = rtabs[curtab++][pptr->b];
- pptr++;
- }
- }
- }
-
- void quantop(pptr,n,nsteps)
- pixel *pptr;
- int n;
- float nsteps;
- {
- int i, isteps, ival;
- unsigned char qtab[256];
-
- isteps = nsteps+0.50;
- if(isteps<2)
- isteps = 2;
- else if(isteps>256)
- isteps = 256;
-
- for(i=0; i<256; i++) {
- ival = isteps*i/256;
- qtab[i] = (255*ival)/(isteps-1);
- }
- applymaptab(pptr,n,qtab);
- }
-
- /* duotone stuff follows */
-
- #define DTTONE (0.50)
- #define DTPOWVAL (2.0)
- float hypfunc();
-
- void duotoneop(pptr,n,r,g,b)
- pixel *pptr;
- int n;
- float r, g, b;
- {
- unsigned char rtab[256];
- unsigned char gtab[256];
- unsigned char btab[256];
- int i, lum;
- int glum, wlum;
- float l;
-
- l = LUM(r,g,b)/DTTONE;
- r = r/l;
- g = g/l;
- b = b/l;
- dtmkcurve(r,rtab);
- dtmkcurve(g,gtab);
- dtmkcurve(b,btab);
- for(i=0; i<256; i++) {
- glum = ILUM(rtab[i],gtab[i],btab[i]);
- wlum = i;
- if(glum>0) {
- rtab[i] = (rtab[i]*wlum+(glum>>1))/glum;
- gtab[i] = (gtab[i]*wlum+(glum>>1))/glum;
- btab[i] = (btab[i]*wlum+(glum>>1))/glum;
- if(rtab[i]>255) rtab[i] = 255;
- if(gtab[i]>255) gtab[i] = 255;
- if(btab[i]>255) btab[i] = 255;
- }
- }
- applymaptab3(pptr,n,rtab,gtab,btab);
- }
-
- dtmkcurve(f,tab)
- float f;
- unsigned char tab[256];
- {
- int i;
- float h, hypval;
-
- if(f<0.05)
- f = 0.05;
- if(f>0.95)
- f = 0.95;
- hypval = 1.0;
- h = hypfunc(hypval,DTPOWVAL,DTTONE);
- if(h>f) {
- while(1) {
- h = hypfunc(hypval,DTPOWVAL,DTTONE);
- if(h<f)
- break;
- hypval += 0.005;
- }
- } else {
- while(1) {
- h = hypfunc(hypval,DTPOWVAL,DTTONE);
- if(h>f)
- break;
- hypval -= 0.005;
- }
- }
- for(i=0; i<256; i++)
- tab[i] = 255.0*hypfunc(hypval,DTPOWVAL,i/(float)255)+0.499;
- }
-
- canvas *makestamp(c,maxxsize,maxysize,filter)
- canvas *c;
- int maxxsize, maxysize, filter;
- {
- canvas *stamp;
- int nx, ny;
-
- if((float)c->xsize/c->ysize > (float)maxxsize/maxysize) {
- nx = maxxsize;
- ny = round((float)nx*c->ysize/c->xsize);
- } else {
- ny = maxysize;
- nx = round((float)ny*c->xsize/c->ysize);
- }
- stamp = newcanvas(nx,ny);
- copycanvas(c,&c->area,stamp,&stamp->area,filter);
- return stamp;
- }
-
- void randcopy(orig,dest)
- canvas *orig, *dest;
- {
- int nx, ny, dx, dy, i;
- canvas *stamp, *clone;
- rct drct;
-
- stamp = makestamp(orig,STAMPSIZE,STAMPSIZE,IMPULSE);
- dx = dest->xsize-stamp->xsize;
- dy = dest->ysize-stamp->ysize;
- for(i=0; i<50; i++) {
- drct = stamp->area;
- rctoffset(&drct,random()%dx,random()%dy);
- clone = clonecanvas(stamp);
- canvasop(clone,cscaleop,0.5+0.5*frand(),0.5+0.5*frand(),0.5*frand());
- copycanvas(clone,&clone->area,dest,&drct,IMPULSE);
- freecanvas(clone);
- flushcanvas(dest);
- }
- freecanvas(stamp);
- }
-
- void canvastile(tile,dest)
- canvas *tile, *dest;
- {
- int x, y, nx, ny;
- rct drct;
-
- nx = 1+((dest->xsize-1)/tile->xsize);
- ny = 1+((dest->ysize-1)/tile->ysize);
- for(y=0; y<ny; y++) {
- for(x=0; x<nx; x++) {
- drct = tile->area;
- rctoffset(&drct,x*tile->xsize,y*tile->ysize);
- copycanvas(tile,&tile->area,dest,&drct,IMPULSE);
- }
- flushcanvas(dest);
- }
- }
-
- /*
- * 3x3 convolution follows
- *
- *
- */
- #define DIVVAL (1024)
- #define NORM(x) ((DIVVAL*(x))/tot)
-
- static calcconv(d,s,xsize,ysize,x1,y1,v00,v01,v02,v10,v11,v12,v20,v21,v22)
- pixel *d, *s;
- int xsize, ysize, x1, y1;
- short v00, v01, v02, v10, v11, v12, v20, v21, v22;
- {
- pixel *sp;
- int r, g, b;
- int x0, x2;
- int y0, y2;
-
- x0 = x1-1;
- if(x0<0) x0 = 0;
- x2 = x1+1;
- if(x2==xsize) x2 = xsize-1;
-
- y0 = y1-1;
- if(y0<0) y0 = 0;
- y2 = y1+1;
- if(y2==ysize) y2 = ysize-1;
-
- sp = s+(xsize*y0);
- r = v00*sp[x0].r+v01*sp[x1].r+v02*sp[x2].r;
- g = v00*sp[x0].g+v01*sp[x1].g+v02*sp[x2].g;
- b = v00*sp[x0].b+v01*sp[x1].b+v02*sp[x2].b;
- sp = s+(xsize*y1);
- r += v10*sp[x0].r+v11*sp[x1].r+v12*sp[x2].r;
- g += v10*sp[x0].g+v11*sp[x1].g+v12*sp[x2].g;
- b += v10*sp[x0].b+v11*sp[x1].b+v12*sp[x2].b;
- sp = s+(xsize*y2);
- r = (r+v20*sp[x0].r+v21*sp[x1].r+v22*sp[x2].r)/DIVVAL;
- g = (g+v20*sp[x0].g+v21*sp[x1].g+v22*sp[x2].g)/DIVVAL;
- b = (b+v20*sp[x0].b+v21*sp[x1].b+v22*sp[x2].b)/DIVVAL;
-
- d = d+(xsize*y1+x1);
- if(r&0xffffff00) {
- if(r<0) d->r = 0; else d->r = 255;
- } else
- d->r = r;
-
- if(g&0xffffff00) {
- if(g<0) d->g = 0; else d->g = 255;
- } else
- d->g = g;
-
- if(b&0xffffff00) {
- if(b<0) d->b = 0; else d->b = 255;
- } else
- d->b = b;
- }
-
- void convolve3(sc,dc,mat)
- canvas *sc, *dc;
- int mat[3][3];
- {
- int xsize, ysize;
- int r, g, b;
- short v00, v01, v02;
- short v10, v11, v12;
- short v20, v21, v22;
- pixel *sp, *dp;
- pixel *s, *d;
- int tot, x, y, nx, ny;
- int bcheck, min, max;
-
- xsize = sc->xsize;
- ysize = sc->ysize;
- if(dc->xsize != xsize || dc->ysize != ysize) {
- fprintf(stderr,"convove3: source and dest canvases must be same size\n");
- return;
- }
- s = (pixel *)sc->data;
- d = (pixel *)dc->data;
- nx = xsize-2;
- ny = ysize-2;
- tot = 0;
- bcheck = 0;
- max = -100000;
- min = 100000;
- for(y=0; y<3; y++) {
- for(x=0; x<3; x++) {
- tot += mat[y][x];
- if(mat[y][x]<0)
- bcheck++;
- if(mat[y][x]<min)
- min = mat[y][x];
- if(mat[y][x]>max)
- max = mat[y][x];
- }
- }
- if(tot == 0)
- tot = 1;
- v00 = NORM(mat[0][0]); v01 = NORM(mat[0][1]); v02 = NORM(mat[0][2]);
- v10 = NORM(mat[1][0]); v11 = NORM(mat[1][1]); v12 = NORM(mat[1][2]);
- v20 = NORM(mat[2][0]); v21 = NORM(mat[2][1]); v22 = NORM(mat[2][2]);
-
- /* do the edges by reflecting values */
- for(y=0; y<ysize; y++) {
- if(y==0 || y == ysize-1) {
- for(x=0; x<xsize; x++)
- calcconv(d,s,xsize,ysize,x,y,v00,v01,v02,v10,v11,v12,v20,v21,v22);
- } else {
- calcconv(d,s,xsize,ysize,0,y,v00,v01,v02,v10,v11,v12,v20,v21,v22);
- if(xsize>1)
- calcconv(d,s,xsize,ysize,xsize-1,y,v00,v01,v02,v10,v11,v12,v20,v21,v22);
- }
- }
-
- /* check for constant kernel */
- if(max == min) {
- for(y=0; y<ny; y++) {
- dp = d+(y+1)*xsize+1;
- sp = s+(y+0)*xsize+0;
- for(x=0; x<nx; x++) {
- r = sp[0].r+sp[1].r+sp[2].r;
- g = sp[0].g+sp[1].g+sp[2].g;
- b = sp[0].b+sp[1].b+sp[2].b;
- sp+=xsize;
- r += sp[0].r+sp[1].r+sp[2].r;
- g += sp[0].g+sp[1].g+sp[2].g;
- b += sp[0].b+sp[1].b+sp[2].b;
- sp+=xsize;
- dp->r = (r+sp[0].r+sp[1].r+sp[2].r)/9;
- dp->g = (g+sp[0].g+sp[1].g+sp[2].g)/9;
- dp->b = (b+sp[0].b+sp[1].b+sp[2].b)/9;
- sp = sp-(2*xsize-1);
- dp++;
- }
- }
- /* do general kernel */
- } else {
- for(y=0; y<ny; y++) {
- dp = d+(y+1)*xsize+1;
- sp = s+(y+0)*xsize+0;
- for(x=0; x<nx; x++) {
- r = v00*sp[0].r+v01*sp[1].r+v02*sp[2].r;
- g = v00*sp[0].g+v01*sp[1].g+v02*sp[2].g;
- b = v00*sp[0].b+v01*sp[1].b+v02*sp[2].b;
- sp+=xsize;
- r += v10*sp[0].r+v11*sp[1].r+v12*sp[2].r;
- g += v10*sp[0].g+v11*sp[1].g+v12*sp[2].g;
- b += v10*sp[0].b+v11*sp[1].b+v12*sp[2].b;
- sp+=xsize;
- r = (r+v20*sp[0].r+v21*sp[1].r+v22*sp[2].r)/DIVVAL;
- g = (g+v20*sp[0].g+v21*sp[1].g+v22*sp[2].g)/DIVVAL;
- b = (b+v20*sp[0].b+v21*sp[1].b+v22*sp[2].b)/DIVVAL;
-
- if(bcheck) {
- if(r&0xffffff00) {
- if(r<0) dp->r = 0; else dp->r = 255;
- } else
- dp->r = r;
-
- if(g&0xffffff00) {
- if(g<0) dp->g = 0; else dp->g = 255;
- } else
- dp->g = g;
-
- if(b&0xffffff00) {
- if(b<0) dp->b = 0; else dp->b = 255;
- } else
- dp->b = b;
- } else {
- dp->r = r;
- dp->g = g;
- dp->b = b;
- }
-
- sp = sp-(2*xsize-1);
- dp++;
- }
- }
- }
- }
-